import { DocumentEventCenter } from "../base_frame/DocumentEventCenter";
import { IShaderBase } from "../base_frame/IShaderBase";
import { Keyboard } from "../base_frame/Keyboard";
import { ShaderBase } from "../base_frame/ShaderBase";
import { ShaderTool } from "../base_frame/ShaderTool";
import { Vector3 } from "../base_frame/math/Vector3";

/**
 *  需要  矩阵相乘的顺序 project * view * module
 *  顺序变化会造成数据计算的错误
 */
export class CameraDemo extends ShaderBase implements IShaderBase {

    protected readonly VS: string =
        "attribute vec4 a_Position;\n" +
        "attribute vec4 a_Color;\n" +
        "uniform mat4 u_MvpMatrix;\n" +
        "varying vec4 v_Color;\n" +
        "void main(){\n" +
        "   v_Color = a_Color;\n" +
        "   gl_Position = u_MvpMatrix * a_Position;\n" +
        "}\n";

    protected readonly FS: string =
        "precision mediump float;\n" +
        "varying vec4 v_Color;\n" +
        "void main(){\n" +
        "   gl_FragColor = v_Color;\n" +
        "}\n";

    protected a_Position: number;
    protected a_Color: number;

    protected eyeVec3: Vector3;
    protected lookVec3: Vector3;

    protected viewMatrix: Matrix4;
    protected projectMatrix: Matrix4;

    protected bufferDatas: Float32Array = new Float32Array([
        -0.3, -0.3, 0.0, 1.0, 0.3, 0.3,
        0.3, -0.3, 0.0, 0.3, 0.3, 0.3,
        0.0, 0.3, 0.0, 1.0, 0.3, 0.3,

        -0.3, -0.3, -2.0, 0.3, 1.0, 0.3,
        0.3, -0.3, -2.0, 0.3, 0.3, 0.3,
        0.0, 0.3, -2.0, 0.3, 1.0, 0.3,

        -0.3, -0.3, -4.0, 0.3, 0.3, 1.0,
        0.3, -0.3, -4.0, 0.3, 0.3, 0.3,
        0.0, 0.3, -4.0, 0.3, 0.3, 1.0,
    ]);
    private _angle: number = 0;
    private _gl: WebGL2RenderingContext | WebGLRenderingContext;

    init(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        if (!initShaders(gl, this.VS, this.FS)) return console.error("init shader fail!!!");
        gl.enable(gl.DEPTH_TEST);
        this.eyeVec3 = new Vector3(0.0, 0.0, 5.0);
        this.lookVec3 = new Vector3(0.0, 0.0, -100.0);
        this.viewMatrix = new Matrix4();
        this.projectMatrix = new Matrix4();
        this.moduleMatrix = new Matrix4();
        this.mvpMatrix = new Matrix4();
        this._gl = gl;
        this.initShaderRef(gl);
        this.initBuffer(gl);
        this.draw(gl);
        DocumentEventCenter.regKeyDown(this, this.onKeyDown, [gl]);

    }

    initShaderRef(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        // @ts-ignore
        let program = gl.program;
        this.a_Position = gl.getAttribLocation(program, "a_Position");
        this.a_Color = gl.getAttribLocation(program, "a_Color");
        this.u_MvpMatrix = gl.getUniformLocation(program, "u_MvpMatrix");
    }

    initBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        this.createBuffer(gl, this.bufferDatas, this.a_Position, 0);
        this.createBuffer(gl, this.bufferDatas, this.a_Color, 3);
    }

    protected createBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext, datas: Float32Array, idx: number, offset: number) {
        let buffer: WebGLBuffer = gl.createBuffer();
        if (!buffer) return console.error("create buffer fail");
        let size = datas.BYTES_PER_ELEMENT;
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, datas, gl.STATIC_DRAW);
        gl.vertexAttribPointer(idx, 3, gl.FLOAT, false, size * 6, size * offset);
        gl.enableVertexAttribArray(idx);
    }

    inputBlur(text: string): void {
        if (text) {
            ShaderTool.setProperty(text, this);
            this.draw(this._gl);
        }
    }


    onKeyDown(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: KeyboardEvent) {
        if (ev.keyCode == Keyboard.A) {
            this.eyeVec3.x -= 0.1;
        }
        if (ev.keyCode == Keyboard.D) {
            this.eyeVec3.x += 0.1;

        }
        if (ev.keyCode == Keyboard.W) {
            this.eyeVec3.z += 0.1;
        }
        if (ev.keyCode == Keyboard.S) {
            this.eyeVec3.z -= 0.1;
        }
        console.log(`eye.x:${this.eyeVec3.x}  eye.y:${this.eyeVec3.y}  eye.z:${this.eyeVec3.z}  `)
        this.draw(gl);
    }

    draw(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        this.viewMatrix.setLookAt(
            this.eyeVec3.x, this.eyeVec3.y, this.eyeVec3.z,
            this.lookVec3.x, this.lookVec3.y, this.lookVec3.z,
            Vector3.Up.x, Vector3.Up.y, Vector3.Up.z,
        );
        this.projectMatrix.setPerspective(60, 1.0, 0.1, 100);

        this.moduleMatrix.setIdentity();
        this.moduleMatrix.setTranslate(0.75, 0.0, 0.0);
        this.mvpMatrix.set(this.projectMatrix).multiply(this.viewMatrix).multiply(this.moduleMatrix);
        gl.uniformMatrix4fv(this.u_MvpMatrix, false, this.mvpMatrix.elements);
        gl.drawArrays(gl.TRIANGLES, 0, 9);

        this.moduleMatrix.setIdentity();
        this.moduleMatrix.setTranslate(-0.75, 0.0, 0.0);
        this.mvpMatrix.set(this.projectMatrix).multiply(this.viewMatrix).multiply(this.moduleMatrix);
        gl.uniformMatrix4fv(this.u_MvpMatrix, false, this.mvpMatrix.elements);
        gl.drawArrays(gl.TRIANGLES, 0, 9);
    }

}